package org.sinuto.documentserver.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.sinuto.documentserver.bean.Document;
import org.sinuto.documentserver.bean.EditorConfig;
import org.sinuto.documentserver.constant.Error;
import org.sinuto.documentserver.exception.DocumentServerException;
import org.sinuto.documentserver.service.DocumentServerService;
import org.sinuto.documentserver.service.FileService;
import org.sinuto.documentserver.utils.DocumentServerUtils;
import org.sinuto.documentserver.utils.FileUtils;
import org.sinuto.documentserver.utils.HttpUtils;
import org.sinuto.documentserver.utils.Log;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Map;
import java.util.Scanner;


/**
 * @Author 2023/2/27 9:07 ly
 **/
@Service
public class DocumentServerServiceImpl implements DocumentServerService {


    @Resource
    private DocumentServerUtils documentServerUtils;

    @Resource
    private FileService fileService;



    @Override
    public Document buildDocument(String id) throws DocumentServerException {
        Map<String, Object> obj = fileService.getFileInfo(id);
        return buildDocument(id, (String) obj.get("path"), (String) obj.get("attach_show_name"));
    }


    private Document buildDocument(String id, String path, String name) throws DocumentServerException {

        String type = documentServerUtils.getType(path);

        // 如果指定了文件名，则需要校验和实体文件格式是否一致
        boolean bln0 = StringUtils.isNotBlank(name);
        if (bln0 && !type.equalsIgnoreCase(FilenameUtils.getExtension(name))) {
            throw DocumentServerException.build(Error.DOC_FILE_EXTENSION_NOT_MATCH);
        }

        File file = new File(FilenameUtils.normalize(path));
        // 校验文件实体
        documentServerUtils.checkFile(file);

        Document document = Document.builder()
                .fileType(type)
                .title(bln0 ? name : file.getName())
//                .storage(filePath)
                .key(documentServerUtils.key(file))
                .url(documentServerUtils.downloadUrl(id))
                .build();

        return document;
    }


    @Override
    public EditorConfig buildEditorConfig(String id, String user) {
        return EditorConfig.builder()
                .callbackUrl(documentServerUtils.callbackUrl(id))
                .user(EditorConfig.User.builder()
                        .id("uid-"+user)
                        .name(user)
                        .build())
                .build();
    }

    @Override
    public void download(String id, HttpServletResponse response) throws IOException {
        Map<String, Object> obj = fileService.getFileInfo(id);
        FileUtils.getResource((String) obj.get("path"), (String) obj.get("attach_show_name"), response);
    }

    @Override
    public void callBack(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String id = request.getParameter("id");
        String filePath = fileService.getFilePath(id);


        Scanner scanner = new Scanner(request.getInputStream()).useDelimiter("\\A");
        String body = scanner.hasNext() ? scanner.next() : "";
        JSONObject js = JSON.parseObject(body);

        PrintWriter writer = response.getWriter();

        String error = "0";
        switch (js.getInteger("status")) {
            // 1 - document is being edited
            case 1:
                Log.info("action: EDITING");
                break;
            // 2 - document is ready for saving
            case 2:
                Log.info("action: SAVE");
                resourceAcquisitionAndSave(js.getString("url"), filePath);
                break;
            // 3 - document saving error has occurred
            case 3:
                Log.info("action: CORRUPTED");
                break;
            case 4:
                Log.info("action: NOT MODIFY");
                break;
            // MUST_FORCE_SAVE 6 - document is being edited, but the current document state is saved
            case 6:
                Log.info("action: MUST_FORCE_SAVE");
                resourceAcquisitionAndSave(js.getString("url"), filePath);
                break;
            // 7 - error has occurred while force saving the document
            case 7:
                Log.info("action: CORRUPTED_FORCE_SAVE");
                resourceAcquisitionAndSave(js.getString("url"), filePath);
                break;
            default:
                Log.info("action: OTHER");

                error = "1";
                break;
        }
        Log.info(js.toString());
//        FileUtil.deleteTempFile(filePath);
        writer.write("{\"error\":" + error + "}");
    }

    private void resourceAcquisitionAndSave(String url, String path) {
        HttpUtils.download(url, (InputStream is) -> FileUtils.save(is, path));
    }

}
